package com.audiobo.recorder;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
import java.security.AccessController;
import java.security.PrivilegedAction;
import javax.sound.sampled.*;

// Referenced classes of package com.audiobo.recorder:
//            VUViewLevelSource, AppletController, AudioCaptureDelegate

class AudioCapture implements Runnable, VUViewLevelSource {

  TargetDataLine line;
  int channels;
  AudioFormat audioFormat;
  javax.sound.sampled.AudioFileFormat.Type targetType;
  int frameSizeInBytes;
  int bufferLengthInBytes;
  private File outputFile;
  private OutputStream audioOutStream;
  double currentLevel;
  double currentPeak;
  double duration;
  double maxRecordingTime;
  AudioCaptureDelegate _flddelegate;

  public static void checkPermissions() throws SecurityException {
    (new AudioPermission("record")).checkGuard(javax.sound.sampled.AudioPermission.class);
  }

  AudioCapture() {
    channels = 1;
    audioFormat = new AudioFormat(
        javax.sound.sampled.AudioFormat.Encoding.PCM_SIGNED, 22050F, 16,
        channels, 2 * channels, 22050F, true);
    targetType = javax.sound.sampled.AudioFileFormat.Type.AIFF;
    outputFile = null;
    maxRecordingTime = 4D;
    cleanUp();
  }

  public void cleanUp() {
    File file = new File(AppletController.audioFilePath);
    if (file.exists() && file.canWrite()) {
      boolean flag = file.delete();
      if (flag) {
        System.out.println("audio Tmp file deleted...");
      }
    }
    file = new File(AppletController.outputTmpFilePath);
    if (file.exists() && file.canWrite()) {
      boolean flag1 = file.delete();
      if (flag1) {
        System.out.println("raw Tmp file deleted...");
      }
    }
    duration = 0.0D;
    if (_flddelegate != null) {
      _flddelegate.updateRecordingTime(duration);
    }
  }

  public boolean start() {
    javax.sound.sampled.DataLine.Info info = new javax.sound.sampled.DataLine.Info(javax.sound.sampled.TargetDataLine.class, audioFormat);
    if (!AudioSystem.isLineSupported(info)) {
      System.err.println((new StringBuilder()).append("Line matching ")
          .append(info).append(" not supported.").toString());
      return false;
    }
    try {
      line = (TargetDataLine) AudioSystem.getLine(info);
      line.open(audioFormat, 7500);
    } catch (LineUnavailableException lineunavailableexception) {
      System.err.println((new StringBuilder())
          .append("Unable to open the line: ").append(lineunavailableexception)
          .toString());
      return false;
    } catch (Exception exception) {
      System.err.println(exception.toString());
      return false;
    }
    audioFormat = line.getFormat();
    frameSizeInBytes = audioFormat.getFrameSize();
    bufferLengthInBytes = line.getBufferSize();
    try {
      System.out.println(AppletController.outputTmpFilePath);
      outputFile = new File(AppletController.outputTmpFilePath);
      duration = (double) outputFile.length()
          / (double) ((float) audioFormat.getFrameSize() * audioFormat
              .getFrameRate());
      FileOutputStream fileoutputstream = new FileOutputStream(outputFile, true);
      audioOutStream = new BufferedOutputStream(fileoutputstream,
          bufferLengthInBytes);
    } catch (FileNotFoundException filenotfoundexception) {
      System.err.println(filenotfoundexception);
    } catch (OutOfMemoryError outofmemoryerror) {
      System.err.println(outofmemoryerror);
    }
    line.start();
    (new Thread(this, "AudioCapture Thread")).start();
    return true;
  }

  public void run() {
    boolean flag = false;
    ByteBuffer bytebuffer = ByteBuffer.allocate(bufferLengthInBytes);
    do {
      int i;
      if (!line.isOpen()
          || (i = line.read(bytebuffer.array(), 0, bufferLengthInBytes)) == -1) {
        break;
      }
      updateTimeValues(i);
      updateLevelAndPeak(bytebuffer, i);
      handleSamples(bytebuffer.array(), i);
      if (duration > maxRecordingTime && !flag) {
        flag = true;
        AccessController.doPrivileged(new PrivilegedAction() {

          public Object run() {
            _flddelegate.recordingShouldStop();
            return null;
          }

        });
      }
    } while (true);
    line.stop();
    line.close();
    line = null;
  }

  public void stop() {
    if (line != null) {
      line.stop();
      line.drain();
      line.close();
      try {
        audioOutStream.close();
        createAIFFFile();
      } catch (Exception exception) {
        System.err.println(exception);
      }
    }
  }

  private void createAIFFFile() throws Exception {
    FileInputStream fileinputstream = new FileInputStream(outputFile);
    long l = outputFile.length();
    BufferedInputStream bufferedinputstream = new BufferedInputStream(
        fileinputstream, bufferLengthInBytes);
    AudioInputStream audioinputstream = new AudioInputStream(
        bufferedinputstream, audioFormat, l / (long) audioFormat.getFrameSize());
    File file = new File(AppletController.audioFilePath);
    AudioSystem.write(audioinputstream, targetType, file);
    bufferedinputstream.close();
  }

  protected void handleSamples(byte abyte0[], int i) {

    try {
      audioOutStream.write(abyte0, 0, i);
    } catch (IOException ioexception) {
      System.err.println(ioexception.toString());
    }
  }

  public void setMaxRecordingTime(double d) {
    maxRecordingTime = d;
  }

  public void setDelegate(AudioCaptureDelegate audiocapturedelegate) {
    _flddelegate = audiocapturedelegate;
  }

  public double getDuration() {
    return duration;
  }

  protected void updateLevelAndPeak(ByteBuffer bytebuffer, int bufferLen) {
    int numFrame = bufferLen / frameSizeInBytes;
    long sampleSqureTotal = 0L;
    long peak = 0L;
    ShortBuffer shortbuffer = bytebuffer.asShortBuffer();
    for (int indexFrame = 0; indexFrame < numFrame; indexFrame++) {
      int sampleValue = 0;
      for (int indexChannel = 0; indexChannel < channels; indexChannel++) {
        sampleValue += shortbuffer.get(channels * indexFrame + indexChannel);
      }

      sampleValue /= channels;
      int k = Math.abs(sampleValue);
      sampleSqureTotal += sampleValue * sampleValue;
      if ((long) k > peak) {
        peak = k;
      }
    }

    currentLevel = numFrame <= 0 ? 0.0D : Math.sqrt(sampleSqureTotal / (long) numFrame);
    currentPeak = peak;
  }

  public double getAudioLevel() {
    return currentLevel / 32768D;
  }

  public double getAudioPeak() {
    return currentPeak / 32768D;
  }

  protected void updateTimeValues(int i) {
    duration += (double) i
        / (double) ((float) audioFormat.getFrameSize() * audioFormat
            .getFrameRate());
    if (_flddelegate != null) {
      _flddelegate.updateRecordingTime(duration);
    }
  }
}
